package BLC

import (
	"fmt"
	"github.com/boltdb/bolt"
	"log"
	"math/big"
	"time"
)

const dbName  ="blockchain.db"

const blockTableName  = "blocks"

type BlockChain struct {
	Tip []byte // 最新的区块的hash
	DB *bolt.DB
}

func (blc *BlockChain) Printchain()  {

	var block *Block
	var currentHash []byte = blc.Tip

	for  {
		err := blc.DB.View(func(tx *bolt.Tx) error {

			b := tx.Bucket([]byte(blockTableName))
			if b != nil {
				// 获取当前区块
				blockBytes := b.Get(currentHash)
				// 反序列化
				block = DeserializeBlock(blockBytes)

				fmt.Printf("Height：%d\n",block.Height)
				fmt.Printf("PrevBlockHash：%x\n",block.PrevBlockHash)
				fmt.Printf("Data：%s\n",block.Data)
				fmt.Printf("Timestamp：%s\n",time.Unix(block.Timestamp,0).Format("2006-01-02 03:04:05 PM"))
				fmt.Printf("Hash：%x\n",block.Hash)
				fmt.Printf("Nonce：%d\n",block.Nonce)

			}

			return nil
		})

		fmt.Println()

		if err != nil {
			log.Panic(err)
		}

		var hashInt big.Int
		hashInt.SetBytes(block.PrevBlockHash)

		if big.NewInt(0).Cmp(&hashInt) == 0 {
			break
		}

		currentHash = block.PrevBlockHash
	}
}

//2 增加区块到区块链里面
func (blc *BlockChain) AddBlockToBlockchain(data string){

	err := blc.DB.Update(func(tx *bolt.Tx) error {

		b := tx.Bucket([]byte(blockTableName))

		if b != nil {

			// 1、要先获取最新区块
			blockBytes := b.Get(blc.Tip)
			// 2、反序列化
			block := DeserializeBlock(blockBytes)
			// 3. 将区块序列化
			newBlock := NewBlock(data,block.Height+1,block.Hash)
			err := b.Put(newBlock.Hash,newBlock.SeriaLize())
			if err != nil {
				log.Panic(err)
			}
			// 4. 更新数据库里面“l”对应的hash
			err = b.Put([]byte("l"),newBlock.Hash)
			if err != nil {
				log.Panic(err)
			}
			//5. 更新blockchain的Tip
			blc.Tip = newBlock.Hash
		}

		return nil
	})

	if err != nil {
		log.Panic(err)
	}
}

// 1. 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *BlockChain{

	// 打开数据库
	db, err := bolt.Open(dbName,0600,nil)
	if err != nil{
		log.Fatal(err)
	}
	var blockHash []byte

	err = db.Update(func(tx *bolt.Tx) error {

		// 创建表
		b := tx.Bucket([]byte(blockTableName))

		if err != nil{
			log.Panic(err)
		}

		if b == nil {
			b , err  = tx.CreateBucket([]byte(blockTableName))
			if err != nil {
				log.Panic(err)
			}

		}
		//创建创始区块
		genesisBlock := CreateGenesisBlock("GenisisBlock Data .....")
		// 存储
		err := b.Put(genesisBlock.Hash,genesisBlock.SeriaLize())
		if err != nil {
			log.Panic(err)
		}

		// 存储最新的区块的hash
		err = b.Put([]byte("l"),genesisBlock.Hash)
		if err != nil {
			log.Panic(err)
		}

		blockHash = genesisBlock.Hash

		return nil
	})



	//反回区块链对象
	return &BlockChain{blockHash,db}
}